package ferp.android.activities;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import ferp.android.BuildConfig;
import ferp.android.GUI;
import ferp.android.R;
import ferp.android.activities.preferences.Preferences;
import ferp.android.dialogs.*;
import ferp.android.engagement.Reminder;
import ferp.android.engagement.Snowfall;
import ferp.android.managers.BonusManager;
import ferp.android.managers.CloudManager;
import ferp.android.managers.ProfileManager;
import ferp.android.managers.UpdateManager;
import ferp.android.social.LikesManager;
import ferp.android.tasks.center.*;
import ferp.android.widgets.buttons.TextButton;
import ferp.core.game.Game;
import ferp.core.game.Settings;
import ferp.core.log.Log;
import ferp.core.player.Profile;

import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;

/**
 * User: olegs
 * Date: 20/02/12 23:39
 */
public class Entrance extends Activity implements TaskProfileDelete.Listener,
                                                  MessageDialog.Listener,
                                                  ErrorDialog.Listener,
                                                  RadioListViewDialog.Listener,
                                                  CloudActionsDialog.Listener,
                                                  TaskProfileImport.Listener,
                                                  ImportProfileDialog.Listener,
                                                  UpdateManager.Listener,
                                                  CloudManager.Listener.Login,
                                                  CloudManager.Listener.Load
{

  @Override
  public void onBeforeProfileDeletion()
  {
    showDialog(Dialogs.PROGRESS_PROFILE_DELETING);
  }

  @Override
  public void onAfterProfileDeletion()
  {
    GUI.tryToDismissDialog(this, Dialogs.PROGRESS_PROFILE_DELETING);

    // restart the activity
    restart();
  }

  @Override
  public void onYesClick(int requestCode)
  {
    switch (requestCode)
    {
      case Dialogs.ALERT_DELETE_PROFILE:
        Profile p = pm.getCurrentProfile();
        new TaskProfileDelete(this, p, this).execute();
        break;

      case Dialogs.ALERT_DELETE_GAME:
        deleteGame();
        break;
    }
  }

  @Override
  public void onNoClick(int requestCode)
  {
  }

  @Override
  public void onCloseClick()
  {
    GUI.tryToDismissDialog(this, Dialogs.ALERT_ERROR);
    finish();
  }

  @Override
  public void onItemSelected(int requestCode, int selected)
  {
    previous = pm.getCurrentProfile();

    Profile current = pm.setCurrentProfile(selected);

    selectProfiles.setText(current.nickname);

    enableWidgets();

    GUI.tryToDismissDialog(this, Dialogs.SELECT_PROFILE);

    if (previous != null)
    {
      // we need to restart after profile has changed (locale, orientation)
      if (!previous.settings.locale.equals(current.settings.locale) || previous.settings.orientation != current.settings.orientation)
        restart();
      else
        // logon if cloud save enabled (for new profiles we will not get here because of the above if statement)
        if (current.settings.cloudSave != Settings.CloudSave.NONE && !cm.isLoggedIn())
          cm.login(this, this);
    }
  }

  @Override
  public void onItemSelected(CloudActionsDialog.Action action)
  {
    switch (action)
    {
      case LOGON:
        cm.login(this, this);
        break;

      case SWITCH_ACCOUNT:
        cm.logout();
        cm.login(this, this);
        break;

      case LOAD_DATA:
        cm.load(this);
        break;

      case LOGOUT:
        cm.logout();
        GUI.toast(this, R.string.toast_cloud_logged_out);
        break;
    }
  }

  @Override
  public void onSaveClick(int requestCode, String value, boolean fromCurrentPosition)
  {
    value = value.trim();

    try
    {
      new TaskProfileImport(this, this, Long.valueOf(value), fromCurrentPosition).execute();
    }
    catch (NumberFormatException e)
    {
      GUI.toast(this, String.format(getResources().getString(R.string.import_profile_invalid_report_id), value));
    }

    GUI.tryToDismissDialog(this, requestCode);
  }

  @Override
  public void onProfileImported(boolean success)
  {
    if (success)
    {
      // refresh GUI
      enableWidgets();
      showProfiles();
    }

    GUI.toast(this, success ? R.string.import_profile_success : R.string.import_profile_fail);
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu)
  {
    Profile p = pm.getCurrentProfile();
    // should we enable menu items related to the current profile
    boolean enable = (p != null);

    // set locale (Android bug !!!)
    Preferences.setLocale(this, p);

    // inflate menu
    getMenuInflater().inflate(R.menu.entrance, menu);

    // resolve settings menu button
    settings = resolveMenuItem(menu, R.id.entrance_settings, android.R.drawable.ic_menu_preferences, enable);
    // resolve score menu button
    score = resolveMenuItem(menu, R.id.entrance_score, R.drawable.ic_menu_score, enable);
    // resolve help menu button
    resolveMenuItem(menu, R.id.entrance_help, android.R.drawable.ic_dialog_info, true);
    // resolve load game menu button
    cloud = menu.findItem(R.id.entrance_cloud);
    cloud.setEnabled(cm.isEnabled());
    // resolve import profile menu button
    resolveMenuItem(menu, R.id.entrance_importProfile, android.R.drawable.stat_sys_download, true).setVisible(BuildConfig.DEBUG);

    return super.onCreateOptionsMenu(menu);
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item)
  {
    switch (item.getItemId())
    {
      case R.id.entrance_settings:
        Profile p = pm.getCurrentProfile();
        onSettings(p != null && !p.hasGame());
        return true;

      case R.id.entrance_score:
        startActivity(new Intent(this, Results.class));
        return true;

      case R.id.entrance_cloud:
        showDialog(Dialogs.CLOUD_ACTIONS);
        return true;

      case R.id.entrance_help:
        startActivity(new Intent(this, Help.class));
        return true;

      case R.id.entrance_importProfile:
        showDialog(Dialogs.IMPORT_PROFILE);
        return true;

      default:
        return super.onOptionsItemSelected(item);
    }
  }

  @Override
  public void onInstall(int code)
  {

  }

  @Override
  public void onCommonUpdate(int from, int to)
  {
    // version 29 removes game object (the change related to save game feature)
    if (from < 29 && to >= 29)
      showDialog(Dialogs.INFORMATION);
  }

  @Override
  public boolean onProfileUpdate(int from, int to, Profile profile)
  {
    boolean result = false;

    // version 35 should recalculate balance (balance2 field was added to score)
    if (from < 35 && to >= 35)
      result = profile.update35();

    if (from < 46 && to >= 46)
      result = profile.update46();

    if (from < 50 && to >= 50)
      result = profile.update50();

    if (from < 54 && to >= 54)
      result = profile.update54();

    return result;
  }

  @Override
  public void onLoginSuccess()
  {
    GUI.toast(this, R.string.toast_cloud_log_in_success);
  }

  @Override
  public void onLoginFail()
  {
    GUI.toast(this, R.string.toast_cloud_log_in_failure);
  }

  @Override
  public void onLoadStart()
  {
    showDialog(Dialogs.PROGRESS_CLOUD_LOAD);
  }

  @Override
  public void onLoadEnd(List<Profile> loaded)
  {
    StringBuilder sb = new StringBuilder();

    if (loaded != null)
    {
      for (Profile p : loaded)
      {
        pm.addProfile(p);
        sb.append("\n  ").append(p.nickname);
      }

      // refresh GUI
      enableWidgets();
      showProfiles();
    }

    GUI.tryToDismissDialog(this, Dialogs.PROGRESS_CLOUD_LOAD);

    GUI.toast(this, sb.length() == 0 ? getString(R.string.toast_cloud_no_profiles_loaded) : getString(R.string.toast_cloud_k_profiles_loaded) + sb);
  }

  @Override
  protected void onCreate(Bundle savedInstanceState)
  {
    // initialize profile manager
    pm = ProfileManager.instance(this);
    cm = CloudManager.instance(this);

    Profile profile = pm.getCurrentProfile();

    // set correct orientation depends on if running on tablet or not
    GUI.setOrientation(this, profile);

    super.onCreate(savedInstanceState);

    if (getIntent().getBooleanExtra(Reminder.ENGAGEMENT, false))
      new TaskEngagement(true).execute();

    Reminder.alarm(this);

    Preferences.setLocale(this, profile);

    //set content view
    setContentView(R.layout.entrance);
    // set copyright
    ((TextView)findViewById(R.id.entrance_copyright)).setText(getResources().getString(R.string.app_copyright, Calendar.getInstance().get(Calendar.YEAR)));
    // resolve and enable widgets
    resolveWidgets();
    enableWidgets();

    if (getFilesDir() != null)
    {
      // perform install/update logic
      UpdateManager.execute(getSharedPreferences(UpdateManager.VERSION, Context.MODE_PRIVATE), pm, this);

      // at this point we know exactly which profiles are hacked
      TaskProfileHacked.report(pm);

      // show profiles
      showProfiles();
      // get configuration from center
      TaskCenterConfigGet.execute(this, pm, (TextView)findViewById(R.id.messages));

      Calendar now = Calendar.getInstance();
      int day = now.get(Calendar.DAY_OF_YEAR);

      // create the snowfall controller only if around the new year
      if (false) // day > 360 || day < 5)
      {
        this.snowfall = new Snowfall(this, (ViewGroup)this.findViewById(R.id.entrance_layout));

        TextView tv = (TextView)findViewById(R.id.happyNewYear);
        tv.setTypeface(GUI.Font.BOLD);
        tv.setVisibility(View.VISIBLE);
      }

      // login to cloud if gms is enabled and not logged in and there is at least one profile with cloud save on
      if (cm.isEnabled() && !cm.isLoggedIn() && pm.hasAtLeastOneProfileWithCloudSaveOn())
        cm.login(this, this);
    }
    else
      showDialog(Dialogs.ALERT_INSTALLATION);

    LikesManager.initialize(this, R.id.entrance_webview_likes, new LikesManager.Listener()
    {
      @Override
      public void onFacebookLikeSet()
      {
        BonusManager.activateOneTimeFacebookBonus(Entrance.this);
      }

      @Override
      public void onFacebookLikeRemoved()
      {
        Log.debug(Log.TAG, "unliked");
      }

      @Override
      public void onGooglePlusOneSet()
      {
        BonusManager.activateOneTimeGooglePlusBonus(Entrance.this);
      }

      @Override
      public void onGooglePlusOneRemoved()
      {
        Log.debug(Log.TAG, "-1");
      }
    });
  }

  @Override
  protected Dialog onCreateDialog(int id)
  {
    switch (id)
    {
      case Dialogs.ALERT_ERROR:
        return new ErrorDialog(this, this);

      case Dialogs.ALERT_INSTALLATION:
        return new ErrorDialog(this, this, R.string.error_installation);

      case Dialogs.SELECT_PROFILE:
        return new RadioListViewDialog(this, this, Dialogs.SELECT_PROFILE);

      case Dialogs.ALERT_DELETE_PROFILE:
        return new MessageDialog(this, this, Dialogs.ALERT_DELETE_PROFILE);

      case Dialogs.ALERT_DELETE_GAME:
        return new MessageDialog(this, this, Dialogs.ALERT_DELETE_GAME);

      case Dialogs.PROGRESS_PROFILE_DELETING:
        return new ProgressDialog(this).set(R.string.please_wait, R.string.profile_deleting);

      case Dialogs.IMPORT_PROFILE:
        return new ImportProfileDialog(this, this, Dialogs.IMPORT_PROFILE);

      case Dialogs.INFORMATION:
        return new InfoDialog(this);

      case Dialogs.PROGRESS_CLOUD_LOAD:
        return new ProgressDialog(this).set(R.string.please_wait, R.string.loading_game_from_cloud);

      case Dialogs.CLOUD_ACTIONS:
        return new CloudActionsDialog(this, this);
    }

    return super.onCreateDialog(id);
  }

  @Override
  protected void onPrepareDialog(int id, Dialog dialog)
  {
    Preferences.setLocale(this, pm.getCurrentProfile());

    super.onPrepareDialog(id, dialog);

    switch (id)
    {
      case Dialogs.SELECT_PROFILE:
        int index = pm.getCurrentProfileIndex();
        ((RadioListViewDialog)dialog).set(getString(R.string.entrance_select_profile), nicknames, index == -1 ? 0 : index);
        break;

      case Dialogs.ALERT_DELETE_PROFILE:
        ((MessageDialog)dialog).set(R.string.warning, String.format(getResources().getString(R.string.warning_delete_profile), pm.getCurrentProfile().nickname));
        break;

      case Dialogs.ALERT_DELETE_GAME:
        ((MessageDialog)dialog).set(R.string.warning, String.format(getResources().getString(R.string.warning_delete_game), pm.getCurrentProfile().nickname));
        break;

      case Dialogs.CLOUD_ACTIONS:
        ((CloudActionsDialog)dialog).prepare(cm);
        break;
    }
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent intent)
  {
    super.onActivityResult(requestCode, resultCode, intent);

    switch (requestCode)
    {
      case SETTINGS:
        // reload the activity as language might have been changed
        restart();
        break;

      case CloudManager.REQUEST_CODE:
        CloudManager.instance(getApplication()).onActivityResult(this, this, resultCode);
        break;
    }
  }

  @Override
  protected void onResume()
  {
    super.onResume();

    // try to start the snowfall
    if (snowfall != null)
      snowfall.start();
  }

  @Override
  protected void onPause()
  {
    super.onPause();

    // try to stop the snowfall
    if (snowfall != null)
      snowfall.stop();
  }

  @Override
  protected void onDestroy()
  {
    GUI.recycle(this, R.id.intro_title);

    super.onDestroy();
  }

  private Snowfall snowfall;

  private void restart()
  {
    finish();
    startActivity(new Intent(this, Entrance.class));
  }

  private void deleteGame()
  {
    try
    {
      Profile profile = pm.getCurrentProfile();
      // get the actual game
      Game game = profile.games().actual;
      // try to obtain the balance
      long gain = game == null ? 0 : game.getHumanScore().balance2.current;

      // positive balance is ignored
      if (gain > 0)
        profile.getStatistics().score[0] -= gain;

      // request game deletion
      TaskGameDelete.execute(this, profile);
      // save current profile without game snapshot
      pm.saveCurrentProfile(true);

      enableWidgets();
    }
    catch (Exception e)
    {
      showDialog(Dialogs.ALERT_ERROR);
      Log.error(Log.TAG, e);
    }
  }

  private void showProfiles()
  {
    // store the currently selected profile for locale change check
    previous = pm.getCurrentProfile();

    // fill nicknames list
    nicknames.clear();

    for (Profile p : pm.getProfileList())
      nicknames.add(p.nickname);

    if (selectProfiles != null)
    {
      Profile p = pm.getCurrentProfile();

      selectProfiles.setText(p == null ? "" : p.nickname);
    }

    // set locale
    Preferences.setLocale(Entrance.this, pm.getCurrentProfile());
  }

  private void resolveWidgets()
  {
    Profile p = pm.getCurrentProfile();
    TextButton createProfile = (TextButton)findViewById(R.id.create_profile);

    selectProfiles = (Button)findViewById(R.id.select_profile);
    selectProfiles.setTypeface(GUI.Font.BOLD);
    selectProfiles.setOnClickListener(new View.OnClickListener()
    {
      @Override
      public void onClick(View view)
      {
        // set locale (Android bug !!!)
        Preferences.setLocale(Entrance.this, pm.getCurrentProfile());

        showDialog(Dialogs.SELECT_PROFILE);
      }
    });
    selectProfiles.setText(p == null ? "" : p.nickname);

    createProfile.setOnClickListener(new View.OnClickListener()
    {
      @Override
      public void onClick(View view)
      {
        try
        {
          pm.newCurrentProfile();

          onSettings(true);
        }
        catch (Exception e)
        {
          showDialog(Dialogs.ALERT_ERROR);
          Log.error(Log.TAG, e);
        }
      }
});

    deleteProfile = (TextButton)findViewById(R.id.delete_profile);
    deleteProfile.setOnClickListener(new View.OnClickListener()
    {
      @Override
      public void onClick(View view)
      {
        // set locale (Android bug !!!)
        Preferences.setLocale(Entrance.this, pm.getCurrentProfile());

        showDialog(Dialogs.ALERT_DELETE_PROFILE);
      }
    });

    newGame = (TextButton)findViewById(R.id.new_game);
    newGame.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view)
      {
        if (view.isClickable())
        {
          // prevent fast clicking
          view.setClickable(false);

          // create new game object
          pm.getCurrentProfile().createGame();
          // create the main activity
          startActivity(new Intent(Entrance.this, Ferp.class));
          // finish this activity
          finish();
        }
      }
    });

    deleteGame = (TextButton)findViewById(R.id.delete_game);
    deleteGame.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view)
      {
        // set locale (Android bug !!!)
        Preferences.setLocale(Entrance.this, pm.getCurrentProfile());

        showDialog(Dialogs.ALERT_DELETE_GAME);
      }
    });

    resumeGame = (TextButton)findViewById(R.id.resume_game);
    resumeGame.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view)
      {
        if (view.isClickable())
        {
          // prevent fast clicking
          view.setClickable(false);

          // reload current profile from disk before resuming as its memory state could be different from the stored one
          pm.reloadCurrentProfile();
          pm.getCurrentProfile().resumeGame();

          // start the main activity
          startActivity(new Intent(Entrance.this, Ferp.class));

          // finish this activity
          finish();
        }
      }
    });
  }

  private void enableWidgets()
  {
    Profile p = pm.getCurrentProfile();
    List<Profile> l = pm.getProfileList();

    // change all required button states
    selectProfiles.setEnabled(l.size() > 0);
    deleteProfile.setEnabled(p != null);
    resumeGame.setEnabled(p != null && p.hasGame());
    newGame.setEnabled(p != null);// && Profile.current.settings.poolSize <= Profile.current.balance);

    newGame.setVisibility(resumeGame.isEnabled() ? View.GONE : View.VISIBLE);
    deleteGame.setVisibility(resumeGame.isEnabled() ? View.VISIBLE : View.GONE);

    if (settings != null)
      settings.setEnabled(p != null);

    if (score != null)
      score.setEnabled(p != null);

/*
    if (loadGame != null)
      loadGame.setEnabled(cm.isLoggedIn());
*/
  }

  private void onSettings(boolean isNewGame)
  {
    // create intent
    Intent intent = new Intent(this, Preferences.class);

    // create bundle for new game
    Bundle b = new Bundle();
    b.putBoolean(Preferences.Intent.NEW_GAME, isNewGame);
    b.putBoolean(Preferences.Intent.ENTRANCE, true);

    // bind bundle to an intent
    intent.putExtras(b);

    // start Preference activity
    startActivityForResult(intent, SETTINGS);
  }

  private MenuItem resolveMenuItem(Menu menu, int id, int iconID, boolean enabled)
  {
    MenuItem mi = menu.findItem(id);

    mi.setIcon(iconID);
    mi.setEnabled(enabled);

    return mi;
  }

  private static final class Dialogs
  {
    private static final int ALERT_ERROR               = 1;
    private static final int ALERT_INSTALLATION        = 2;
    private static final int SELECT_PROFILE            = 3;
    private static final int ALERT_DELETE_PROFILE      = 4;
    private static final int ALERT_DELETE_GAME         = 5;
    private static final int PROGRESS_PROFILE_DELETING = 6;
    private static final int IMPORT_PROFILE            = 7;
    private static final int INFORMATION               = 8;
    private static final int PROGRESS_CLOUD_LOAD       = 9;
    private static final int CLOUD_ACTIONS             = 10;
  }

  // activity results
  private static final int SETTINGS = 1;

  // profile manager
  private ProfileManager pm;
  // cloud manager
  private CloudManager cm;
  // profile selection data structures
  private List<String> nicknames = new LinkedList<String>();
  // previous profile to compare if locale has been changed or not
  private Profile previous;

  // widgets
  private Button selectProfiles;
  private TextButton deleteProfile;
  private TextButton newGame;
  private TextButton deleteGame;
  private TextButton resumeGame;

  // menu items
  private MenuItem settings;
  private MenuItem score;
  private MenuItem cloud;
}